﻿using System;
using System.Collections.Generic;
using IQIGame.Onigao.Framework;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public class BulletComponent : TComponent
    {
        public UnitView unit;

        protected override void OnDispose()
        {
            this.unit = null;
            this.remove.Clear();
            for (int i = 0; i < this.bullets.Count; i++)
            {
                ClassPool.Put(this.bullets[i]);
            }
            this.bullets.Clear();
        }

        public override void OnCreate(TEntity entity)
        {
            this.unit = entity as UnitView;
        }

        // 全量子弹
        private List<Bullet> bullets = new List<Bullet>();
        // 待移除子弹
        private List<Bullet> remove = new List<Bullet>();

        public override void OnUpdate(float deltaTime)
        {
            base.OnUpdate(deltaTime);
            for (int i = 0; i < this.bullets.Count; i++)
            {
                var rBullet = this.bullets[i];
                rBullet.curTime += deltaTime;

                if (rBullet.duration > 0)
                {
                    var fRate = rBullet.curTime / rBullet.duration;
                    var rPosRate = rBullet.path.GetPosition(fRate);
                    var rEffect = BattleEffectManager.Instance.GetEffect(rBullet.effect);
                    if (rEffect != null)
                    {
                        rEffect.targetPos = Vector3.Scale(new Vector3(1, 1, Math.Max(0, rBullet.length)), rPosRate) * (rBullet.flyBack ? -1 : 1);
                        var fScale = Mathf.Lerp(rBullet.startScale, rBullet.endScale, fRate);
                        rEffect.targetScale = new Vector3(fScale, fScale, fScale);
                    }
                    if (rPosRate.z >= 1)
                    {
                        this.BulletHit(rBullet);
                    }
                }
                else
                {
                    this.BulletHit(rBullet);
                }
            }
            for (int i = 0; i < this.remove.Count; i++)
            {
                var rBullet = this.remove[i];
                this.bullets.Remove(this.remove[i]);
                ClassPool.Put(rBullet);
            }
            this.remove.Clear();
        }

        public void AddBulletToTarget(string effectName, int startDummy, Vector3 startDeviation, Vector3 endDeviation, UnitView targetUnit, int targetDummy, float speed, Action onHit)
        {
            if (!string.IsNullOrEmpty(effectName))
            {
                var rBullet = this.CreateBullet(effectName, startDummy, startDeviation, endDeviation, targetUnit, targetDummy, speed, onHit);
                this.bullets.Add(rBullet);
            }
        }
        
        public void AddBulletToPos(string effectName, int startDummy, Vector3 startDeviation, Vector3 endDeviation,Vector3 targetPos, float speed, Action onHit)
        {
            if (!string.IsNullOrEmpty(effectName))
            {
                var rBullet = this.CreateBullet(effectName, startDummy, startDeviation, endDeviation, targetPos, speed, onHit);
                this.bullets.Add(rBullet);
            }
        }

        public void BulletHit(Bullet rBullet)
        {
            rBullet.onHit?.Invoke();
            this.RemoveBullet(rBullet);
        }

        public void RemoveBullet(Bullet bullet)
        {
            this.remove.Add(bullet);
            BattleEffectManager.Instance.Stop(bullet.effect);
        }

        // 创建子弹，当前仍是指向一个位置，保留此方法便于修改为以transform为目标
        private Bullet CreateBullet(string rEffectName, int nStartDummy, Vector3 startShifting, Vector3 endShifting, UnitView rTarget, int nTargetDummy, float fSpeed, Action rOnHit)
        {
            var rBullet = ClassPool.Get<Bullet>();
            var rViewComp = this.unit.GetComponent<UnitViewComponent>(ETComponentType.UnitViewComponent);
            var rBind = this.unit.GetComponent<BattleViewBindPointComponent>(ETComponentType.BattleViewBindPointComponent);
            var rEffectComp = this.unit.GetComponent<EffectComponent>(ETComponentType.EffectComponent);

            Transform rStartTrans = rBind.GetBindPoint(nStartDummy);

            var rTargetBind = rTarget.GetComponent<BattleViewBindPointComponent>(ETComponentType.BattleViewBindPointComponent);
            var rTargetTrans = rTargetBind.GetBindPoint(nTargetDummy);

            var rStartDeviation = Vector3.zero;
            if (startShifting != Vector3.zero)
            {
                // 策划需求根据角色转朝向，不管骨骼点
                var rDummyQua = rViewComp.transform.rotation;
                var rDevLen = startShifting.magnitude;
                var rQuaDev = Quaternion.LookRotation(startShifting.normalized);
                var rDevRot = rDummyQua * rQuaDev;
                rStartDeviation = rDevRot * Vector3.forward * rDevLen;
            }

            rBullet.startPos = rStartTrans.position + rStartDeviation;
            rBullet.curPos = rBullet.startPos;
            rBullet.targetPos = rTargetTrans.position;
            rBullet.targetTrans = rTargetTrans;
            var rAspect = rBullet.targetPos - rBullet.startPos;
            if (endShifting != Vector3.zero)
            {
                rAspect.y = 0;
                var rDevLen = endShifting.magnitude;
                var rDevRot = rAspect.normalized * rDevLen;
                rBullet.targetPos -= rDevRot;
                rAspect = rBullet.targetPos - rBullet.startPos;
            }

            rBullet.length = rAspect.magnitude;
            rBullet.onHit = rOnHit;
            if (rAspect == Vector3.zero)
            {
                rAspect = rViewComp.forward;
            }
            rBullet.path = new BulletPath_Curve();
            var rDistance = rBullet.length;
            rBullet.duration = rDistance / fSpeed;

            // 子弹飞行方向与角色朝向夹角超过90，就认为需要反向飞行
            var rUnitLookAt = rViewComp.forward;
            var fDot = Vector3.Dot(rAspect.normalized, rUnitLookAt.normalized);
            if (fDot < 0)
            {
                rBullet.flyBack = true;
                rAspect = -rAspect;
            }
            // 用一个骚方法把子弹特效的初始朝向指定为子弹的前进方向，这样在对其内部修改位置的时候，可以不去计算旋转直接使用localposition
            rBullet.effect = rEffectComp.AddBulletEffect(rEffectName, rBullet.startPos,
                Quaternion.LookRotation(rAspect, Vector3.up));
            return rBullet;
        }
        
        // 创建固定坐标点目标的子弹
        private Bullet CreateBullet(string rEffectName, int nStartDummy, Vector3 startShifting, Vector3 endShifting, Vector3 targetPos, float fSpeed, Action rOnHit)
        {
            var rBullet = ClassPool.Get<Bullet>();
            var rViewComp = this.unit.GetComponent<UnitViewComponent>(ETComponentType.UnitViewComponent);
            var rBind = this.unit.GetComponent<BattleViewBindPointComponent>(ETComponentType.BattleViewBindPointComponent);
            var rEffectComp = this.unit.GetComponent<EffectComponent>(ETComponentType.EffectComponent);

            Transform rStartTrans = rBind.GetBindPoint(nStartDummy);

            var rStartDeviation = Vector3.zero;
            if (startShifting != Vector3.zero)
            {
                // 策划需求根据角色转朝向，不管骨骼点
                var rDummyQua = rViewComp.transform.rotation;
                var rDevLen = startShifting.magnitude;
                var rQuaDev = Quaternion.LookRotation(startShifting.normalized);
                var rDevRot = rDummyQua * rQuaDev;
                rStartDeviation = rDevRot * Vector3.forward * rDevLen;
            }

            rBullet.startPos = rStartTrans.position + rStartDeviation;
            rBullet.curPos = rBullet.startPos;
            rBullet.targetPos = targetPos;
            var rAspect = rBullet.targetPos - rBullet.startPos;
            if (endShifting != Vector3.zero)
            {
                rAspect.y = 0;
                var rDevLen = endShifting.magnitude;
                var rDevRot = rAspect.normalized * rDevLen;
                rBullet.targetPos -= rDevRot;
                rAspect = rBullet.targetPos - rBullet.startPos;
            }

            rBullet.length = rAspect.magnitude;
            rBullet.onHit = rOnHit;
            if (rAspect == Vector3.zero)
            {
                rAspect = rViewComp.forward;
            }
            rBullet.path = new BulletPath_Curve();
            var rDistance = rBullet.length;
            rBullet.duration = rDistance / fSpeed;

            // 子弹飞行方向与角色朝向夹角超过90，就认为需要反向飞行
            var rUnitLookAt = rViewComp.forward;
            var fDot = Vector3.Dot(rAspect.normalized, rUnitLookAt.normalized);
            if (fDot < 0)
            {
                rBullet.flyBack = true;
                rAspect = -rAspect;
            }
            // 用一个骚方法把子弹特效的初始朝向指定为子弹的前进方向，这样在对其内部修改位置的时候，可以不去计算旋转直接使用localposition
            rBullet.effect = rEffectComp.AddBulletEffect(rEffectName, rBullet.startPos,
                Quaternion.LookRotation(rAspect, Vector3.up));
            return rBullet;
        }
    }
}